using System;
using System.Linq;
using RomanJendrusz.Amazon.ETL.Domain;
using RomanJendrusz.Amazon.ETL.Infrastructure.DataBase;

namespace RomanJendrusz.Amazon.ETL.Repositories
{
    public class BookRepository : Repository<Book, string>, IBookRepository
    {
        private readonly IAuthorRepository authorRepository;
        private readonly ICustomerReviewRepository customerReviewRepository;

        public BookRepository(ISession session, ICustomerReviewRepository customerReviewRepository,
                              IAuthorRepository authorRepository) : base(session, s => s.Books, "Asin")
        {
            this.customerReviewRepository = customerReviewRepository;
            this.authorRepository = authorRepository;
        }

        #region IBookRepository Members

        public Book AttachIfAllreadyExists(Book item)
        {
            if (item == null)
            {
                return null;
            }
            Book book = FindBy(item.Asin);
            if (book != null)
            {
                attachToPersistedBook(item, book);
            }
            else
            {
                book = item;
                //Add(book);
                attachBooksChildrens(item, book);
            }

            return book;
        }

        public SimiliarBook FindSimiliarity(Book book, Book similiarTo)
        {
            return session.SimiliarBooks.SingleOrDefault(sb => sb.Book == book && sb.BooksSimiliarTo == similiarTo);
        }


        public Book FindBookByISBN(string isbn, DateTime newerThen)
        {
            return source.SingleOrDefault(b => b.ISBN == isbn && b.Updated > newerThen);
        }

        #endregion

        private void attachBooksChildrens(Book item, Book book)
        {
            foreach (BookAuthors author in book.BookAuthors)
            {
                attachAuthorIfAllreadyExists(author);
            }
            for (int i = 0; i < item.CustomerReviews.Count; i++)
            {
                customerReviewRepository.AttachIfAllreadyExists(item.CustomerReviews[i]);
            }
        }

        private void attachToPersistedBook(Book item, Book book)
        {
            attach(item, book);
            foreach (BookAuthors author in item.BookAuthors)
            {
                if (author.Author != null)
                {
                    Author persistedAuthor = session.Authors.Where(a => a.FullName == author.Author.FullName)
                        .SingleOrDefault(a => a.BookAuthors.SingleOrDefault(ba => ba.Book == book) != null);
                    if (persistedAuthor == null)
                    {
                        attachAuthorIfAllreadyExists(author);
                        book.BookAuthors.Add(author);
                    }
                }
            }
            for (int i = 0; i < item.CustomerReviews.Count; i++)
            {
                CustomerReview customerReview = customerReviewRepository.AttachIfAllreadyExists(item.CustomerReviews[i]);
                book.CustomerReviews.Add(customerReview);
            }
            for (int i = 0; i < item.SimiliarBooks.Count; i++)
            {
                SimiliarBook persistedSimiliarity = session.SimiliarBooks.SingleOrDefault(
                    sb =>
                    sb.Book == item.SimiliarBooks[i].Book && sb.BooksSimiliarTo == item.SimiliarBooks[i].BooksSimiliarTo);
                if (persistedSimiliarity == null)
                {
                    book.SimiliarBooks.Add(item.SimiliarBooks[i]);
                }
                else
                {
                    book.SimiliarBooks.Add(persistedSimiliarity);
                }
            }
        }

        private void attachAuthorIfAllreadyExists(BookAuthors author)
        {
            if (author.Author == null)
            {
                return;
            }
            Author persistedAuthor = authorRepository.FindByName(author.Author.FullName);
            if (persistedAuthor != null)
            {
                author.Author = persistedAuthor;
            }
        }

        private void attach(Book attached, Book orginal)
        {
            orginal.Asin = attached.Asin;
            orginal.Binding = attached.Binding;
            orginal.DetailPageURL = attached.DetailPageURL;
            orginal.EAN = attached.EAN;
            orginal.Height = attached.Height;
            orginal.ISBN = attached.ISBN;
            orginal.Label = attached.Label;
            orginal.Language = attached.Language;
            orginal.Length = attached.Length;
            orginal.Manufacturer = attached.Manufacturer;
            orginal.NumberOfItems = attached.NumberOfItems;
            orginal.NumberOfPages = attached.NumberOfPages;
            orginal.Price = attached.Price;
            orginal.PriceCurrency = attached.PriceCurrency;
            orginal.PublicationDate = attached.PublicationDate;
            orginal.Publisher = attached.Publisher;
            orginal.Studio = attached.Studio;
            orginal.Title = attached.Title;
            orginal.UPC = attached.UPC;
            orginal.Weight = attached.Weight;
            orginal.Width = attached.Width;
        }

        #region IBookRepository Members

        public Book FindBookByAsin(string asin, DateTime newerThen)
        {
            return source.SingleOrDefault(b => b.Asin == asin && b.Updated > newerThen);
        }

        #endregion
    }
}